// Padlo.cpp : Defines the entry point for the console application.
//

#include "block.h"
#include "tileMap.h"
#include <iostream>

int main ()
{
	//HINT: Should call it manually, because the blocks will point to datas in the AllBlockContainers, so after that you MUST rebuild the blocks.
	//Block's rebuild can't call it, because unfortunately it would be an infinite loop.
	TileMap* tileMap = TileMap::getInstance ();
	//tileMap->writeTileMap(std::cout);
	std::cout <<std::endl;
	const int numof0 = tileMap->countNum(0);
	const int numof1 = tileMap->countNum(1);
	const int numof2 = tileMap->countNum(2);
	int firstUsedNumber = 0;
	int firstUsedSize = numof0;
	// Select the num which for the countNum is the minimal.
    if (numof1 < numof0 || numof2 < numof0 ) {
        if (numof1 > numof0) {
            firstUsedNumber = 1;
            firstUsedSize = numof1;
        }
        else{
            firstUsedNumber = 2;
            firstUsedSize = numof2;
        }
    }

    Block::rebuildAllPossibleBlock (1);
    // Search for the block which has the most potential size
    const std::vector<Block>& blocks = Block::getAllPossibleBlock (firstUsedNumber);
    int potentialBlockSize = 0;
    int blockSize = 0;
    size_t blockId = 0;
    // TODO: get the maxBlocksize for all blocks which have same maxPotentialBlockSize
    for (size_t i = 0; i < blocks.size(); ++i) {
        Block currentBlock(blocks[i].getStartingPoint(), firstUsedNumber, 2);
        if (currentBlock.countPotentialBlockSize() > potentialBlockSize) {
            potentialBlockSize = currentBlock.countPotentialBlockSize();
            blockSize = currentBlock.getBlockSize();
            blockId = i;
        }
        else if (currentBlock.countPotentialBlockSize() == potentialBlockSize &&
                 currentBlock.getBlockSize()> blockSize)
        {
            blockSize = currentBlock.getBlockSize();
            blockId = i;
        }

    }

    Coord usedStartingPoint = blocks[blockId].getStartingPoint();
    bool done = false;
    while (!done) {
        Block usedBlock(usedStartingPoint, firstUsedNumber, 2);

        std::queue<Block> notLinkables = usedBlock.getNotLinkableBlocks();
        std::vector<PrimTileMap> holes = usedBlock.getHoles();
        // If we have holes, fill them.
        if (!holes.empty())
        {
            for (auto& hole : holes) {
                    tileMap->insertBlockToFill(hole);
            }
            int linkableIterator = usedBlock.getLinkableBlocks().size();
            // Fill them all!
            while (!tileMap->isToFillEmpty()) {
                if (!tileMap->isFromFillEmpty()){
                    tileMap->doStep();
                }

                else if (!notLinkables.empty()) {
                    tileMap->insertBlockFromFill(notLinkables.front().getBlock());
                    notLinkables.pop();
                }
                else {
                    if ( linkableIterator > 0) {
                        --linkableIterator;
                        tileMap->insertBlockFromFill(
                                usedBlock.getLinkableBlocks()[linkableIterator].first->getBlock());
                    }
                    // TODO: if no linkable block, make a cut.
                }
            }
        }
        // We have no holes, we need to link.
        else {
            tileMap->insertCoordToFill(usedBlock.calculateNextLinkingPoint());
            // Fill them all!
            // TODO: this is a duplication of the above
            int linkableIterator = usedBlock.getLinkableBlocks().size();
            while (!tileMap->isToFillEmpty()) {
                if (!tileMap->isFromFillEmpty()){
                    tileMap->doStep();
                }
                else if (!notLinkables.empty()) {
                    tileMap->insertBlockFromFill(notLinkables.front().getBlock());
                    notLinkables.pop();
                }
                else {
                    if ( linkableIterator > 0) {
                        --linkableIterator;
                        tileMap->insertBlockFromFill(
                                usedBlock.getLinkableBlocks()[linkableIterator].first->getBlock());
                    }
                    // TODO: if no linkable block, make a cut.
                }
            }
        }
        Block::rebuildAllPossibleBlock (1);
        if (usedBlock.getBlockSize() == firstUsedSize) {
            done = true;
        }
    }
        // TODO: make a done condition.
    tileMap->writeTileMap(std::cout);
    //tileMap->writeSteps(std::cout);
    // TODO: unmovable points.
    // TODO: second number
    return 0;
}
